package com.pingan.haofang.searchcloud.api.query.parser.dbobject.sqlnode.function;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;

import com.pingan.haofang.searchcloud.api.query.parser.dbobject.FunctionConfig;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.GroupBySupport;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.SqlNode;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.exception.FunctionExecuteException;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.sqlnode.ColumnNode;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.util.SqlNodeUtil;

/**
 * range_group('fieldName', begin, end, gap, [....]);
 * 
 * @author LUYI374
 * @date 2018年3月19日
 * @since 1.0.0
 */
public class RangeGroup extends Function implements GroupBySupport {

    public static final int MAX_SIZE = 10000;

    private List<RangeGroupGapNode> gapNodeList;

    public RangeGroup() {
        setName(FunctionConfig.RANGE_GROUP.name);
        gapNodeList = new ArrayList<>();
    }

    @Override
    public int getParamCount() {
        return getParams().size();
    }

    @Override
    public void validate() {
        List<SqlNode> params = getParams();
        if (CollectionUtils.isEmpty(params) || params.size() < 4 || (params.size() - 1) % 3 != 0) {
            throw new FunctionExecuteException(
                    "params is illegal, expect range_group('fieldName', begin, end, gap, [....])");
        }
        if (!SqlNodeUtil.isColumn(params.get(0))) {
            throw new FunctionExecuteException(
                    "params is illegal, expect range_group('fieldName', begin, end, gap, [....])");
        }

        int totalGapRangeSize = 0;

        long lastEnd = -1L;
        for (int i = 1; i < params.size(); i += 3) {
            SqlNode beginNode = params.get(i);
            SqlNode endNode = params.get(i + 1);
            SqlNode gapNode = params.get(i + 2);
            if (!SqlNodeUtil.isConstant(beginNode) || !(beginNode.getValue() instanceof Number)
                    || !SqlNodeUtil.isConstant(endNode) || !(endNode.getValue() instanceof Number)
                    || !SqlNodeUtil.isConstant(gapNode) || !(gapNode.getValue() instanceof Number)) {
                throw new FunctionExecuteException(
                        "params is illegal, expect range_group('fieldName', begin, end, gap, [....])");
            }
            if (Long.valueOf(String.valueOf(beginNode.getValue())) <= lastEnd) {
                throw new FunctionExecuteException(
                        "params is illegal, expect range_group('fieldName', begin, end, gap, [....])");
            }

            RangeGroupGapNode node = new RangeGroupGapNode(Integer.valueOf(String.valueOf(beginNode.getValue())),
                    Integer.valueOf(String.valueOf(endNode.getValue())),
                    Integer.valueOf(String.valueOf(gapNode.getValue())));

            int gapRangeSize = (node.getEnd() - node.getBegin()) / node.getGap();

            gapNodeList.add(node);
            totalGapRangeSize += gapRangeSize;
        }

        if (totalGapRangeSize > MAX_SIZE) {
            throw new FunctionExecuteException(
                    "params is illegal, totally range scope cannot be more than " + MAX_SIZE);
        }
    }

    @Override
    public ColumnNode getColumn() {
        return (ColumnNode) getParams().get(0);
    }

    @Override
    public boolean exclusive() {
        return true;
    }

    public List<RangeGroupGapNode> getGapNodeList() {
        return gapNodeList;
    }
}
